package cConsole

import (
	"fmt"
	"reflect"
	"sync"
)

var version = "unknown"

type Console struct {
	Args   []string
	Cmd    string
	Method string
	Params map[string]string
}

type ConsoleContainer struct {
	lock      sync.RWMutex
	instances map[string]ConsoleInterface
	params    map[string][]string

	console *Console
}

func (i *ConsoleContainer) Save(instance any) bool {
	i.lock.Lock()
	defer i.lock.Unlock()

	desc := instance.(ConsoleInterface).Desc()
	i.instances[desc.Name] = instance.(ConsoleInterface)
	for _, method := range desc.Methods {
		key := fmt.Sprintf("%s::%s", desc.Name, method.Name)
		i.params[key] = []string{}
		for _, param := range method.Params {
			i.params[key] = append(i.params[key], param.Name)
		}
	}

	return true
}

func (i *ConsoleContainer) Get(name string) any {
	i.lock.RLock()
	defer i.lock.RUnlock()

	return i.instances[name]
}

func (i *ConsoleContainer) Remove(name string) bool {
	return true
}

func (i *ConsoleContainer) Is(instance any) bool {
	return reflect.TypeOf(instance).Implements(reflect.TypeOf((*ConsoleInterface)(nil)).Elem())
}

func (i *ConsoleContainer) Range(f func(instance any)) {
	i.lock.RLock()
	defer i.lock.RUnlock()

	for _, item := range i.instances {
		f(item)
	}
}

func (i *ConsoleContainer) GetParams(name, method string) []string {
	i.lock.RLock()
	defer i.lock.RUnlock()

	key := fmt.Sprintf("%s::%s", name, method)
	return i.params[key]
}

func (i *ConsoleContainer) SetConsole(cmd, method string, params map[string]string) {
	i.lock.RLock()
	defer i.lock.RUnlock()

	i.console = &Console{
		Cmd:    cmd,
		Method: method,
		Params: params,
	}
}

func (i *ConsoleContainer) GetConsole() *Console {
	i.lock.RLock()
	defer i.lock.RUnlock()

	return i.console
}

var container = &ConsoleContainer{
	instances: make(map[string]ConsoleInterface),
	params:    make(map[string][]string),
	console:   nil,
}
